#include "SDL/SDL_gfxPrimitives.h"
#include "Editor.h"
#include <iomanip>
#include <iostream>
#include <errno.h>
#include <dirent.h>

using namespace std;


void Editor::drawOutline(SDL_Surface* screen)
{
    int curs_x = 0;
    int curs_y = 0;

    SDL_GetMouseState(&curs_x, &curs_y);

    if(curs_y < WINDOW_HEIGHT - bar->bounds->h)
    {
        curs_x += camera.get_x();
        curs_y += camera.get_y();

        if(!outline.empty() && drawing)
        {
            while(curs_x > outline[outline.size()-1].x + 32 || curs_y > outline[outline.size()-1].y + 32 || curs_x < outline[outline.size()-1].x - 32 || curs_y < outline[outline.size()-1].y - 32)
            {
                int pointx =outline[outline.size()-1].x;
                int pointy =outline[outline.size()-1].y;

                if(curs_x > outline[outline.size()-1].x + 32)
                    pointx += 32;
                else if(curs_x < outline[outline.size()-1].x - 32)
                    pointx -= 32;
                if (curs_y > outline[outline.size()-1].y + 32)
                    pointy += 32;
                else if (curs_y < outline[outline.size()-1].y - 32)
                    pointy -= 32;

                addPoint(pointx, pointy);

            }
        }

        if(drawing)
            addPoint(curs_x, curs_y);

        Coord prevcord;

        for(int i = 0; i<outline.size(); i++)
        {
            if(i>0)
            {
                lineColor(screen, prevcord.x-camera.get_x(), prevcord.y-camera.get_y(), outline[i].x-camera.get_x(), outline[i].y-camera.get_y(), (Uint32)0xFF3333FF);
            }

            prevcord.x = outline[i].x;
            prevcord.y = outline[i].y;
        }

        if(!outline.empty() && drawing)
            lineColor( screen,
                   outline[outline.size() -1].x - camera.get_x(),
                   outline[outline.size() -1].y - camera.get_y(),
                   curs_x - camera.get_x(),
                   curs_y - camera.get_y(),
                   (Uint32)0xFFFFFFFF);
    }
}

void Editor::closeOutline()
{
    for(int i = 0; i < map.get_Tiles().size(); i++)
    {
        tileOutline(map.get_Tiles()[i]);
    }

    drawing = false;
    outline.clear();
}

/*
    Uses the even-odd rule to determine which of 8 points on a tile are inside the polygon.
    It then determines what the tile should be based on which points are inside.
*/
void Editor::tileOutline(Tile* tile)
{
    SDL_Rect* box = tile->get_box();
    int tile_x = box->x*32;
    int tile_y = box->y*32;

    Coord TL = {tile_x+7, tile_y+2};
    Coord TR = {tile_x+25, tile_y+2};
    Coord RT = {tile_x+30, tile_y+7};
    Coord RB = {tile_x+30, tile_y+25};
    Coord BR = {tile_x+25, tile_y+30};
    Coord BL = {tile_x+7, tile_y+30};
    Coord LB = {tile_x+2, tile_y+25};
    Coord LT = {tile_x+2, tile_y+7};

    bool bTL = pointInside(TL);
    bool bTR = pointInside(TR);
    bool bRT = pointInside(RT);
    bool bRB = pointInside(RB);
    bool bBR = pointInside(BR);
    bool bBL = pointInside(BL);
    bool bLB = pointInside(LB);
    bool bLT = pointInside(LT);

    if(bTL && bTR && bRT && bRB && bBR && bBL && bLB && bLT)
        tile->set_type(2);
    else if(bTL && bTR && bRT && !bRB && !bBR && !bBL && !bLB && bLT)
        tile->set_type(30);
    else if(!bTL && bTR && bRT && bRB && bBR && !bBL && !bLB && !bLT)
        tile->set_type(31);
    else if(bTL && !bTR && !bRT && !bRB && !bBR && bBL && bLB && bLT)
        tile->set_type(32);
    else if(!bTL && !bTR && !bRT && bRB && bBR && bBL && bLB && !bLT)
        tile->set_type(33);
    else if(!bTL && !bTR && bRT && bRB && bBR && bBL && !bLB && !bLT)
        tile->set_type(19);
    else if(bTL && bTR && !bRT && !bRB && !bBR && !bBL && bLB && bLT)
        tile->set_type(11);
    else if(bTL && bTR && bRT && bRB && !bBR && !bBL && !bLB && !bLT)
        tile->set_type(12);
    else if(!bTL && !bTR && !bRT && !bRB && bBR && bBL && bLB && bLT)
        tile->set_type(18);
    else if(!bTL && !bTR && !bRT && !bRB && bBR && bBL && bLB && !bLT)
        tile->set_type(6);
    else if(!bTL && !bTR && !bRT && bRB && bBR && bBL && !bLB && !bLT)
        tile->set_type(3);
    else if(bTL && bTR && !bRT && !bRB && !bBR && !bBL && !bLB && bLT)
        tile->set_type(27);
    else if(bTL && bTR && bRT && !bRB && !bBR && !bBL && !bLB && !bLT)
        tile->set_type(24);
    else if(!bTL && !bTR && !bRT && !bRB && !bBR && bBL && bLB && bLT)
        tile->set_type(29);
    else if(!bTL && !bTR && bRT && bRB && bBR && !bBL && !bLB && !bLT)
        tile->set_type(28);
    else if(!bTL && bTR && bRT && bRB && !bBR && !bBL && !bLB && !bLT)
        tile->set_type(49);
    else if(bTL && !bTR && !bRT && !bRB && !bBR && !bBL && bLB && bLT)
        tile->set_type(50);
    else if(!bTL && !bTR && !bRT && bRB && bBR && bBL && bLB && bLT)
        tile->set_type(5);
    else if(!bTL && !bTR && bRT && bRB && bBR && bBL && bLB && !bLT)
        tile->set_type(4);
    else if(bTL && bTR && bRT && !bRB && !bBR && !bBL && bLB && bLT)
        tile->set_type(26);
    else if(bTL && bTR && bRT && bRB && !bBR && !bBL && !bLB && bLT)
        tile->set_type(25);
    else if(bTL && !bTR && !bRT && !bRB && bBR && bBL && bLB && bLT)
        tile->set_type(36);
    else if(!bTL && bTR && bRT && bRB && bBR && bBL && !bLB && !bLT)
        tile->set_type(35);
    else if(bTL && bTR && bRT && bRB && bBR && !bBL && !bLB && !bLT)
        tile->set_type(42);
    else if(bTL && bTR && !bRT && !bRB && !bBR && bBL && bLB && bLT)
        tile->set_type(43);
}

/*
    Determines if a given point is within the polygon.
*/
bool Editor::pointInside(Coord point)
{
    //if a ray from a point crosses an odd number of lines of the polygon, it is inside
    int cross = 0;

    for(int i = 0; i<outline.size(); i++)
    {
        int k = i+1;
        if (k == outline.size())
            k = 0;

        if(crosses(point, outline[i], outline[k]))
            cross++;
    }

    if(cross%2 != 0)
        return true;

    return false;
}

/*
    Calculates whether a ray going left from "point" crosses over a line segment with points "start" and "end"
*/
bool Editor::crosses(Coord point, Coord start, Coord end)
{
    //horizontal line
    if(start.y == end.y)
    {
        return false;
    }
    //vertical line
    else if(start.x == end.x)
    {
        if(point.x > start.x)
        {
            if(start.y > end.y && point.y <= start.y && point.y>= end.y)
                return true;
            else if( end.y > start.y && point.y >= start.y && point.y<= end.y)
                return true;
        }
    }

    if((start.y > end.y && point.y <= start.y && point.y>= end.y) || ( end.y > start.y && point.y >= start.y && point.y<= end.y))
    {
        Coord rayend = point;
        rayend.x = 0;
        bool first = false;
        bool second = false;

        if(((start.x - end.x)*(point.y - start.y) - (start.y - end.y)*(point.x - start.x)) >= 0)
            first = true;
        if(((start.x - end.x)*(rayend.y - start.y) - (start.y - end.y)*(rayend.x - start.x)) >= 0)
            second = true;

        if(first != second)
            return true;
    }


    return false;
}

bool Editor::pointAt(int x, int y)
{
    for(int i=0; i<outline.size(); i++)
    {
        if(outline[i].x == x && outline[i].y == y)
            return true;
    }
    return false;
}

void Editor::addPoint(int curs_x, int curs_y)
{
    if((curs_x  - (curs_x / 16 *16)) > (((curs_x+16) / 16 *16) - curs_x))
        curs_x += 16;
    if((curs_y  - (curs_y / 16 *16)) > (((curs_y+16) / 16 *16) - curs_y))
        curs_y += 16;

    if(((curs_x/16)%2 || (curs_y/16)%2) && !outline.empty())
    {
        if(abs(curs_x  - (curs_x/16*16)) > 6 || abs(curs_y  - (curs_y/16*16)) > 6)
            return;
    }

    curs_x /= 16;
    curs_y /= 16;

    if((curs_x)%2 != 0 && (curs_y)%2 != 0)
        return;

    if(!outline.empty())
    {
        int prev_x = outline[outline.size() -1].x/16;
        int prev_y = outline[outline.size() -1].y/16;

        if(curs_x%2 || curs_y%2)
        {
            if((curs_x == prev_x+1 || curs_x ==prev_x-1) && (curs_y == prev_y+1 || curs_y == prev_y-1))
                return;
        }
        if((prev_x%2==0) && (prev_y%2==0))
        {
            if((curs_x == prev_x+1 || curs_x ==prev_x-1) && (curs_y == prev_y))
                return;
            if ((curs_x == prev_x) && (curs_y == prev_y+1 || curs_y == prev_y-1))
                return;
        }
    }

    curs_x*=16;
    curs_y*=16;

    for(int i = outline.size() - 1; i>=0; i--)
    {
        if(outline[i].x == curs_x && outline[i].y == curs_y && i != outline.size() -1 )
        {
            if(outline.size() > 2 && i == 0)
                closeOutline();
            else if(i != outline.size() - 1)
            {
                int k = i;
                i=outline.size();
                outline.resize(k);
            }
        }
    }

    if(outline.empty() || outline[outline.size()-1].x != curs_x || outline[outline.size()-1].y != curs_y)
    {
        Coord newcord;
        newcord.x = curs_x;
        newcord.y = curs_y;
        outline.push_back(newcord);
    }

}

void Editor::brushAndErase()
{
    int x, y;
    Uint8 mouse = SDL_GetMouseState(&x, &y);

    if(y < WINDOW_HEIGHT - bar->bounds->h)
    {
        x += camera.get_bounds()->x;
        y += camera.get_bounds()->y;

        Tile* tile =  map.get_Tilepx(x, y);

        //LMB state
        if (mouse & SDL_BUTTON(SDL_BUTTON_LEFT))
        {
            if(bar->tool == BRUSH)
                tile->set_type(2);
            else if(bar->tool == ERASER)
                tile->set_type(0);
        }
        //RMB state
        else if (mouse & SDL_BUTTON(SDL_BUTTON_RIGHT))
        {
            if(bar->tool == BRUSH)
                tile->set_type(1);
        }
    }

}

void Editor::tileCycle(bool rightClick)
{
    int curs_x = 0;
    int curs_y = 0;

    SDL_GetMouseState(&curs_x, &curs_y);

    if(curs_y < WINDOW_HEIGHT - bar->bounds->h)
    {
        curs_x += camera.get_bounds()->x;
        curs_y += camera.get_bounds()->y;

        Tile* tile =  map.get_Tilepx(curs_x, curs_y);

        if(!rightClick)
        {
            switch(tile->get_type())
            {
                case 0: tile->set_type(2); break;
                case 1: tile->set_type(18); break;
                case 2: tile->set_type(1); break;

                case 11: case 12: case 18:
                case 19: tile->set_type(6); break;

                case 3: case 6: case 24: case 27: case 28: case 29: case 49:
                case 50: tile->set_type(5); break;

                case 4: case 5: case 25: case 26: case 35: case 36: case 42:
                case 43: tile->set_type(33); break;

                case 30: case 31: case 32:
                case 33: tile->set_type(0); break;

            }
        }else if(rightClick)
        {
            switch(tile->get_type())
            {
                case 0: tile->set_type(2); break;
                case 1: tile->set_type(0); break;
                case 2: tile->set_type(1); break;
                case 11: tile->set_type(12); break;
                case 12: tile->set_type(19); break;
                case 19:tile->set_type(18); break;
                case 18: tile->set_type(11); break;
                case 3: tile->set_type(6); break;
                case 6: tile->set_type(29); break;
                case 29: tile->set_type(50); break;
                case 50: tile->set_type(27); break;
                case 27: tile->set_type(24); break;
                case 24: tile->set_type(49); break;
                case 49: tile->set_type(28); break;
                case 28: tile->set_type(3); break;
                case 4: tile->set_type(5); break;
                case 5: tile->set_type(36); break;
                case 36: tile->set_type(43); break;
                case 43: tile->set_type(26); break;
                case 26: tile->set_type(25); break;
                case 25: tile->set_type(42); break;
                case 42: tile->set_type(35); break;
                case 35: tile->set_type(4); break;
                case 33: tile->set_type(32); break;
                case 32: tile->set_type(30); break;
                case 30: tile->set_type(31); break;
                case 31: tile->set_type(33); break;
            }
        }
    }
}

void Editor::display_tiles(SDL_Surface* screen)
{
    if(preview)
    {
        map.drawMap(screen, camera.get_bounds());
        map.drawObjects(camera.get_bounds(), screen, "foreground");
    }
    else
    {
        SDL_Rect rect; rect.x=0; rect.y=0; rect.w=WINDOW_WIDTH; rect.h=WINDOW_HEIGHT-bar->bounds->h;
        switch(bar->mode)
        {
            case TERRAIN:
                                artist->drawBox(&rect, (Uint32)0x0000b9);
                                displayBlueprint(screen); break;
            case BG_DECORATION:artist->drawBox(&rect, (Uint32)0xfbff94);
                                map.drawObjects(camera.get_bounds(), screen, "background", true);
                                displayBlueprint(screen);break;
            case FG_DECORATION: artist->drawBox(&rect, (Uint32)0xfdffc0);
                                map.drawObjects(camera.get_bounds(), screen, "background", true);
                                displayBlueprint(screen);
                                map.drawObjects(camera.get_bounds(), screen, "foreground", true);break;
        }
    }

}

void Editor::displayBlueprint(SDL_Surface* screen)
{
    std::vector<Tile*> tiles = map.get_Tiles();

    if(tiles.empty())
        return;

    for(vector<Tile*>::iterator tile = tiles.begin(); tile != tiles.end(); tile++)
    {
        blitTile( screen, *tile);
    }
}

void Editor::blitTile(SDL_Surface* screen, Tile* tile){
	SDL_Rect* cam = camera.get_bounds();

	if(	(tile->get_box()->x*32 >= cam->x-32 				//if the tile is within the left side of the screen
		&& tile->get_box()->x*32 < cam->x+cam->w)				//if the tile is within the right side of the screen
		&& (tile->get_box()->y*32 >= cam->y-32 			//if the tile is within the top of the screen
		&& tile->get_box()->y*32 < cam->y+cam->h)){ 			//if the tile is within the bottom of the screen

        switch(bar->mode)
        {
            case TERRAIN: SDL_BlitSurface( blueprint, &getTileFromSheet(tile->get_type()), screen, &getTileScreenCoord(tile)); break;
            case BG_DECORATION:
            case FG_DECORATION: SDL_BlitSurface( yellowgraph, &getTileFromSheet(tile->get_type()), screen, &getTileScreenCoord(tile));
        }
	}
}

int Editor::interpret(  int tile,
                        int topleft,
                        int top,
                        int topright,
                        int left,
                        int right,
                        int bottomleft,
                        int bottom,
                        int bottomright
                     )
{

    if((top == 2 || top == 33 || top == 4 || top == 5) && (right == 2 || right == 32 || right == 36 || right == 43) && (left == 2 || left==31 || left == 35 || left ==42) && (bottom == 2 || bottom == 30 || bottom == 25 || bottom == 26) && topleft && topleft!=1 && topright && topright!=1 && bottomleft && bottomleft!=1 && bottomright && bottomright!=1)
        tile = 15;
    else if(((top == 0 || top == 30) || top == 1 || ((!topleft || topleft == 1) && (!topright || topright == 1)))&& (right == 2 || right == 5 || right == 32 || right == 18 || right == 5 || right == 29) && (left == 2 || left==31 || left == 19 || left == 4 || left == 28) &&
             (bottom == 2 || bottom == 30 || bottom ==25 || bottom ==26 || bottom == 43) && (bottomleft && bottomleft!= 1) && (bottomright && bottomright != 1))
        tile = 8;
    else if((top == 2 || top == 33 || top == 18 || top == 36 || top == 6 || top == 36) && (right == 0 || right == 1 || right == 31 || ((!topright || topright==1)&& (!bottomright || bottomright == 1))) && (left == 2 || left==31 || left==35 || left == 42 || left == 4) && (bottom == 2 || bottom == 30 || bottom == 11 || bottom == 43 || bottom == 27) && topleft && topleft!=1 && bottomleft && bottomleft!=1)
        tile = 16;
    else if((top == 2 || top == 33 || top == 19 || top == 35 || top == 3 || top == 35) && (right == 2 || right == 32 || right == 36 || right == 43) &&
            (left == 0 || left == 1 || left == 32 || ((!topleft || topleft ==1)&&( !bottomleft || bottomleft == 1))) && (bottom == 2 || bottom == 30 || bottom == 12 || bottom == 42 || bottom == 24 || bottom == 42) && topright && topright!=1 && bottomright && bottomright!=1)
        tile = 14;
    else if((top == 2 || top == 33  || top == 4 || top == 5) && (right == 2 || right == 32 || right == 11 || right == 26 || right == 50 || right == 26) && (left == 2 || left==31 || left == 12 || left == 25 || left == 49 || left == 25) &&
            (bottom == 0 || bottom == 1 || bottom ==33 || ((!bottomleft || bottomleft==1)&& (!bottomright || bottomright == 1))) && topleft && topleft!=1 && topright && topright != 1)
        tile = 22;
    else if((top == 2 || top == 19 || top == 35 || top == 3) && (left == 0 || left == 1 || left == 32 || ((!topleft || topleft ==1)&&( !bottomleft || bottomleft == 1))) && (bottom == 0 || bottom == 1 || bottom ==33 || ((!bottomleft || bottomleft==1)&& (!bottomright || bottomright == 1))) && (right == 2 || right == 11 || right == 50 || right == 26) && topright && topright!=1)
        tile = 21;
    else if((top == 2 || top == 18 || top == 6 || top == 36) && (left== 2 || left == 12 || left == 49 || left == 25) && (bottom == 0 || bottom == 1 || bottom ==33 || ((!bottomleft || bottomleft==1)&& (!bottomright || bottomright == 1))) && (!right || right == 1 || right == 31 || ((!topright || topright==1)&& (!bottomright || bottomright == 1))) && topleft && topleft!=1)
        tile = 23;
    else if(((top == 0 || top == 30) || top == 1 || ((!topleft || topleft == 1)&& (!topright || topright == 1))) && (left == 0 || left == 1 || left == 32 || ((!topleft || topleft ==1)&&( !bottomleft || bottomleft == 1))) && (bottom == 2 || bottom == 24 || bottom == 12 || bottom == 42) && (right == 2 || right == 18 || right == 5 || right == 29) && bottomright && bottomright!=1)
        tile = 7;
    else if(((top == 0 || top == 30) || top == 1 || ((!topleft || topleft == 1)&& (!topright || topright == 1 ))) && (left== 2 || left == 12 || left == 49 || left == 25) && (bottom == 2 || bottom == 27 || bottom == 11 || bottom == 43) && (!right || right==1 || right==31 || ((!bottomright || bottomright==1) && ((!topright || topright == 1 )))) && bottomleft && bottomleft != 1)
        tile = 9;
    else if(left && top && bottom && right && top!=1 && right != 1 && left != 1 && bottom!=1)
    {
        if((bottomright == 0 || bottomright == 1 ||bottomright == 18 || bottomright == 29 || bottomright == 5 || bottomright == 24 || bottomright == 12 || bottomright == 42 || bottomright == 27 || bottomright == 30 ) &&
               (topleft == 0 || topleft == 1 ||topleft == 12 || topleft == 49 || topleft == 25 || topleft == 6 || topleft == 18 || topleft == 36) && bottom != 30 && bottom != 26 && left!=31 && left != 35)
            tile = 41;
        else if((bottomleft == 0 || bottomleft == 1 || bottomleft == 19 || bottomleft == 28 || bottomleft == 4 || bottomleft == 27 || bottomleft == 11 || bottomleft == 43 || bottomleft == 24 || bottomleft == 30 ) &&
                (topright == 0 || topright == 1 || topright == 11 || topright == 50 || topright == 26 || topright == 3 || topright == 19 || topright == 35) && bottom != 30 && bottom != 25 && right!=32 && right != 36)
            tile = 34;
        else if((bottomright == 0 || bottomright == 1 || bottomright == 18 || bottomright == 29 || bottomright == 5 || bottomright == 24 || bottomright == 12 || bottomright == 42 ||  bottomright == 27 || bottomright == 30 ) && bottom != 30 && bottom != 26 && bottom!=24 && bottom!= 12)
            tile = 10;
        else if((topleft == 0 || topleft == 1 || topleft == 12 || topleft == 49 || topleft == 25 || topleft == 6 || topleft == 18 || topleft == 36) && left!=31 && left != 35)
            tile = 20;
        else if((bottomleft == 0 || bottomleft == 1 || bottomleft == 19 || bottomleft == 28 || bottomleft == 4 || bottomleft == 27 || bottomleft == 11 || bottomleft == 43 || bottomleft == 24 || bottomleft == 30 ) && bottom != 30 && bottom != 25 && bottom!= 27 && bottom!= 11)
            tile = 13;
        else if((topright == 0 || topright == 1 || topright == 11 || topright == 50 || topright == 26 || topright == 3 || topright == 19 || topright == 35) && right!=32 && right != 36 && top != 33)
            tile = 17;
    }
    return tile;
}

void Editor::interpretTerrain()
{

    std::vector<Tile*> tiles = map.get_Tiles();

    if(tiles.empty())
        return;

    int current= 0;
    int topleft= 0;
    int top= 0;
    int topright= 0;
    int left= 0;
    int right= 0;
    int bottomleft= 0;
    int bottom= 0;
    int bottomright= 0;

    int width = map.get_Width();
    //int height = map.get_Height();

    for(int i = 0; i< tiles.size(); i++)
    {
        current = tiles[i] -> get_type();

        if(simplify(current) == 2)
        {
            if((i+1)%width != 0 || !i)
            {
                if(i >= width)
                    topright = simplify(tiles[i-width+1] -> get_type());
                else
                    topright = 2;

                right = simplify(tiles[i+1] -> get_type());

                if(i < tiles.size()-width)
                    bottomright = simplify(tiles[i+width+1] -> get_type());
                else
                    bottomright = 2;
            }
            else
            {
                right = 2;
                topright = 2;
                bottomright = 2;
            }

            if(i!=0 && i%width != 0)
            {
                if(i >= width)
                    topleft = simplify(tiles[i-width-1] -> get_type());
                else
                    topleft = 2;

                left = simplify(tiles[i-1] -> get_type());

                if(i < tiles.size()-width)
                    bottomleft = simplify(tiles[i+width-1] -> get_type());
                else
                    bottomleft = 2;
            }
            else
            {
                topleft = 2;
                left = 2;
                bottomleft = 2;
            }
            if(i >= width)
                top = simplify(tiles[i-width] -> get_type());
            else
                top = 2;

            if(i < tiles.size()-width)
                bottom = simplify(tiles[i+width] -> get_type());
            else
                bottom = 2;
            tiles[i]->set_type ( interpret(current, topleft, top, topright, left, right, bottomleft, bottom, bottomright) );
        }
    }
}

int Editor::simplify(int type)
{
    if(type == 2 || (type>=7 && type<=9) || (type>=14 && type <= 16) || (type>=21 && type <= 23) || type == 34 || type == 41 || type == 10 || type == 13 || type == 17 || type == 20)
        return 2;

    return type;
}

void Editor::simplifyTiles()
{
    vector<Tile*> tiles = map.get_Tiles();

    if(tiles.empty())
        return;

    for(std::vector<Tile*>::iterator tile = tiles.begin(); tile != tiles.end(); tile++)
    {
        Tile* mytile = *tile;
        int type = mytile->get_type();

        mytile->set_type(simplify(type));
    }
}

SDL_Rect Editor::getTileFromSheet(int type)
{
    SDL_Rect box;
    box.x=0;  box.y=0;
    box.w=32; box.h=32;
    if(!type)
        return box;
    else if(type == 2)
        box.x=32;
    else if (type == 1)
        box.x=64;
    else if (type >= 30 && type <=33)
    {
        box.y=32;
        box.x= (type-30)*32;
    }
    else if (type == 19)
        box.y =64;
    else if (type == 11)
    {
        box.x = 32;
        box.y = 64;
    }
    else if (type == 12)
    {
        box.x = 64;
        box.y = 64;
    }
    else if( type == 18)
    {
        box.x = 96;
        box.y = 64;
    }
    else if( type == 6)
        box.y=96;
    else if( type == 3)
    {
        box.x=32;
        box.y=96;
    }
    else if( type == 27)
    {
        box.x=64;
        box.y=96;
    }
    else if( type == 24)
    {
        box.x=96;
        box.y=96;
    }
    else if( type == 29)
    {
        box.y=128;
    }
    else if( type == 28)
    {
        box.x=32;
        box.y=128;
    }
    else if( type == 49)
    {
        box.x=64;
        box.y=128;
    }
    else if( type == 50)
    {
        box.x=96;
        box.y=128;
    }
    else if( type == 5)
        box.y=160;
    else if( type == 4)
    {
        box.x=32;
        box.y=160;
    }
    else if( type == 26)
    {
        box.x=64;
        box.y=160;
    }
    else if( type == 25)
    {
        box.x=96;
        box.y=160;
    }
    else if( type == 36)
        box.y=192;
    else if( type == 35)
    {
        box.x=32;
        box.y=192;
    }
    else if( type == 42)
    {
        box.x=64;
        box.y=192;
    }
    else if( type == 43)
    {
        box.x=96;
        box.y=192;
    }

    return box;
}

SDL_Rect Editor::getTileScreenCoord(Tile* tile){
	SDL_Rect screenCoord;
	screenCoord.x = tile->get_box()->x*32 - camera.get_bounds()->x;
	screenCoord.y = tile->get_box()->y*32 - camera.get_bounds()->y;
	return screenCoord;
}



void Editor::createDefaultMap()
{
    map.set_theme("underground");
    map.set_Width(30);
    map.set_Height(30);
    map.empty();

    saveMap("data/maps/custom.map");
}

void Editor::resizeMap(int newWidth, int newHeight)
{
    int oldWidth = map.get_Width();
    int oldHeight = map.get_Height();

    if(newWidth < WINDOW_WIDTH/32)
        newWidth = WINDOW_WIDTH/32;
    if(newHeight < WINDOW_HEIGHT/32)
        newHeight = WINDOW_HEIGHT/32;
    if(newHeight > 200)
        newHeight = 200;
    if(newWidth > 200)
        newWidth = 200;

    vector<Tile*>* tiles = map.get_TilesPointer();

    vector<Tile*> tilescopy = map.get_Tiles();

    if (newWidth < oldWidth)
    {
        for(int k = 0; k < oldHeight; k++)
        {
            for (int i = newWidth; i < oldWidth; i++)
            {
                tilescopy[k*oldWidth + i]->set_type(-1);
            }
        }
        for(vector<Tile*>::iterator it = tiles->begin(); it != tiles->end(); it++)
        {
            Tile* tile = *it;
            if(tile->get_type() == -1)
            {
                tiles->erase(it);
                it--;
            }
        }
    }

    if(newHeight < oldHeight)
    {
        tiles->resize(map.get_Width() * newHeight);
    }

    if(newWidth > oldWidth)
    {
        int k;
        if (newHeight < oldHeight)
            k = newHeight;
        else
            k = oldHeight;
        for (; k>0; k--)
        {
            for(int i = oldWidth; i<newWidth; i++)
            {
            Tile* tile = new Tile(i,k-1,0);
            tiles->insert( tiles->begin() + (oldWidth * k) + i-oldWidth, 1, tile);
            }
        }

    }

    if(newHeight> oldHeight)
    {
        for (int k = oldHeight; k<newHeight; k++)
        {
            for(int i = 0; i<newWidth; i++)
            {
            Tile* tile = new Tile(i,k,0);
            tiles->push_back(tile);
            }
        }
    }

    map.set_Width(newWidth);
    map.set_Height(newHeight);

}

void Editor::removeSelected()
{
    string layer;

    if(bar->mode == BG_DECORATION)
        layer = "background";
    else if(bar->mode == FG_DECORATION)
        layer = "foreground";
    else
        return;

    vector<Object*>* objects = map.getObjects(layer);

    if(objects == NULL || objects->empty())
    {
        cout << "cannot remove; no objects in layer " << layer <<endl;
        return;
    }

    if(layer == "background" && bg_select >= 0 && bg_select < objects->size())
    {
        objects->erase(objects->begin() + bg_select);
        bg_select = -1;
    }
    if(layer == "foreground" && fg_select >= 0 && fg_select < objects->size())
    {
        objects->erase(objects->begin() + fg_select);
        fg_select = -1;
    }
}

void Editor::rotateSelected(Direction dir)
{
    string layer;

    if(bar->mode == BG_DECORATION)
        layer = "background";
    else if(bar->mode == FG_DECORATION)
        layer = "foreground";
    else
        return;

    vector<Object*>* objects = map.getObjects(layer);

    if(objects == NULL || objects->empty())
    {
        cout << "cannot rotate; no objects in layer " << layer <<endl;
        return;
    }

    if(layer == "background" && bg_select >= 0 && bg_select < objects->size())
    {
        objects->at(bg_select)->rotate(*artist, dir, false);
    }
    if(layer == "foreground" && fg_select >= 0 && fg_select < objects->size())
    {
        objects->at(fg_select)->rotate(*artist, dir, false);
    }
}

void Editor::nudgeSelectionBG(Direction dir, int amount)
{
    vector<Object*>* objects = map.getObjects("background");

    if(objects == NULL || objects->empty() || bg_select < 0 || bg_select >= objects->size())
    {
        cout << "cannot nudge, object not in background layer "<<endl;
        return;
    }

    SDL_Rect* bounds = objects->at(bg_select)->get_bounds();
    nudgeSelection(bounds, dir, amount);
}

void Editor::nudgeSelectionFG(Direction dir, int amount)
{
    vector<Object*>* objects = map.getObjects("foreground");

    if(objects == NULL || objects->empty() || fg_select < 0 || fg_select >= objects->size())
    {
        cout << "cannot nudge, object not in background layer "<<endl;
        return;
    }

    SDL_Rect* bounds = objects->at(fg_select)->get_bounds();
    nudgeSelection(bounds, dir, amount);
}

void Editor::nudgeSelection(SDL_Rect* bounds, Direction dir, int amount)
{
    switch(dir)
    {
        case UP:    if(bounds->y > amount)
                      bounds->y -= amount;
                    else
                      bounds->y = 0;
                    break;
        case DOWN:  bounds->y += amount; break;
        case LEFT:  if(bounds->x > amount)
                      bounds->x -= amount;
                    else
                      bounds->x = 0;
                    break;
        case RIGHT: bounds->x += amount; break;
    }

    if(bounds->w != NULL)
        if(bounds->x + bounds->w > map.get_Widthpx())
            bounds->x = map.get_Widthpx() - bounds->w;

    if(bounds->h != NULL)
        if(bounds->y + bounds->h > map.get_Heightpx())
            bounds->y = map.get_Heightpx() - bounds->h;
}

void Editor::readObjectsDirectory()
{
    bar->objectFiles.clear();

    DIR *pdir;
    struct dirent *pent;

    pdir=opendir("./data/objects"); // open directory
    if (!pdir)
    {
        cout << "opendir() failure; terminating";
        return;
    }
    errno=0;

    //read directory "." and put entries into objectFiles

    std::cout << "\n --- traversing directory --- " << std::endl;
    while ((pent=readdir(pdir)))
    {
        bar->objectFiles.push_back(std::string(pent->d_name));
	}

    for (int i = 0; i < bar->objectFiles.size(); i++)
    {
        cout << " adding > " << i << ": " << bar->objectFiles[i] << endl;
    }

    for(int i = 0; i < bar->objectFiles.size(); i++)
    {
        unsigned int lastMatchPos = bar->objectFiles[i].rfind(".obj"); // Find the last occurrence of .obj
        if(lastMatchPos == std::string::npos) // it is not found
        {
            cout << "removing " << bar->objectFiles[i] << endl;
            bar->objectFiles.erase(bar->objectFiles.begin() + i);
            i--;
        }
        else if(lastMatchPos != bar->objectFiles[i].size() - 4) // .obj is not at the end of the string
        {
            cout << "removing " << bar->objectFiles[i] << endl;
            cout << "target position was " << bar->objectFiles[i].size() - 4 << endl;
            cout << "lastMatchPos is " << lastMatchPos << endl;
            bar->objectFiles.erase(bar->objectFiles.begin() + i);
            i--;
        }
        else if(bar->objectFiles[i].find("DEC"))
        {
            cout << "removing non-decoration object: " << bar->objectFiles[i] << endl;
            bar->objectFiles.erase(bar->objectFiles.begin() + i);
            i--;
        }
    }

    if(!bar->objectFiles.empty())
    {
        cout << "\nRevised filename vector: \n";
        bar->objectBank.clear();

        int x = 0;
        int y = 0;
        bool stacked = false;

        for (int i = 0; i < bar->objectFiles.size(); i++)
        {
            cout << "   > " << bar->objectFiles[i] << endl;

            string type = bar->objectFiles[i];
            type.resize(type.size() - 4);

            if(i>0 && bar->objectBank[i-1]->get_bounds_copy().w<=32 && bar->objectBank[i-1]->get_bounds_copy().h<=32)
            {
                stacked = !stacked;
            }
            if (i>0 && (y > 0 || bar->objectBank[i-1]->get_bounds_copy().w > 32))
            {
                stacked = false;
                x += bar->objectBank[i-1]->get_bounds_copy().w + 2;
                //cout << "object[" << i-1 << "] width = " << bar->objectBank[i-1]->get_bounds_copy().w << "\n";
            }

            stacked?y=34:y=0;

            bar->objectBank.push_back(new Object(x, y, type, UP));
            bar->objectBank[i]->set_image(*artist);

            SDL_Rect* bounds = bar->objectBank[i]->get_bounds();

            if(i > 0 && stacked && bounds->h > 32)
            {
                bounds->y = 0;
                bounds->x +=  bar->objectBank[i-1]->get_bounds_copy().w + 2;
                stacked = false;
            }
        }
    }
    else
        cout << "\nNo .obj files found.\n";
}

void Editor::selectObject(std::string layer)
{
    vector<Object*>* objects = map.getObjects(layer);

    if(objects == NULL || objects->empty())
    {
        cout << "cannot select; no objects in layer " << layer <<endl;
        return;
    }

    int curs_x = 0;
    int curs_y = 0;

    SDL_GetMouseState(&curs_x, &curs_y);

    curs_x += camera.get_x();
    curs_y += camera.get_y();

    int first, last;

    if(layer == "background")
    {
        if(bg_select >= 0 && bg_select < objects->size() - 1 && objects->size() > 1)
            first = bg_select + 1;
        else
            first = 0;

        bg_select = -1;
    }
    else if(layer == "foreground")
    {
        if(fg_select >= 0 && fg_select < objects->size() - 1 && objects->size() > 1)
            first = fg_select + 1;
        else
            first = 0;

        fg_select = -1;
    }

    SDL_Rect rect = objects->at(first)->get_bounds_copy();
    if(rect.x <= curs_x && (rect.x + rect.w) >= curs_x && rect.y <= curs_y && (rect.y + rect.h) >= curs_y)
    {
        if(layer == "background")
        {
            bg_select = first;
            cout << "Selected background object[" << bg_select << "]\n";
        }
        else if (layer == "foreground")
        {
            fg_select = first;
            cout << "Selected foreground object[" << fg_select << "]\n";
        }

        return;
    }

    last = first;
    first += 1;

    if(first >= objects->size())
        first = 0;

    for(int i = first; i != last; i++)
    {
        SDL_Rect rect = objects->at(i)->get_bounds_copy();
        if(rect.x <= curs_x && (rect.x + rect.w) >= curs_x && rect.y <= curs_y && (rect.y + rect.h) >= curs_y)
        {
            if(layer == "background")
                bg_select = i;
            else if (layer == "foreground")
                fg_select = i;

            break;
        }

        if(i == objects -> size() -1 && objects->size() > 1)
            i = -1;
    }

    if(layer == "background")
        cout << "Selected background object[" << bg_select << "]\n";
    else if(layer == "foreground")
        cout << "Selected foreground object[" << fg_select << "]\n";

}

void Editor::saveMap(string filepath)
{
    ofstream save(filepath.c_str());

	save << "THEME\n" << map.get_theme() << "\n\n";
	save << "SIZE\n" << map.get_Width() << " " << map.get_Height() << "\n\n";

    std::vector<Tile*> tiles = map.get_Tiles();

    save << "TERRAIN\n";

    interpretTerrain();

    int tilenum = 0;

    for(vector<Tile*>::iterator tile = tiles.begin(); tile != tiles.end(); tile++)
    {
        if(tilenum == map.get_Width())
        {
            tilenum = 1;
            save << "\n";
        }else{
            tilenum++;
        }
        Tile* mytile = *tile;

        save << setfill ('0') << setw (2) << mytile->get_type() << " ";
    }

    save << "\n";

    if(!preview)
        simplifyTiles();

    std::vector<Object*>* bg_objs = map.getObjects("background");

    if(bg_objs && !bg_objs->empty())
    {
        save << "\nOBJECT_LAYER\nbackground\n";
        for(int i = 0; i < bg_objs->size(); i++)
        {
            ObjectInfo info = bg_objs->at(i)->get_info();
            save << info.type << " " << info.x << " " << info.y << " ";
            switch(info.orientation)
            {
                case UP: save << "UP\n"; break;
                case DOWN: save << "DOWN\n"; break;
                case LEFT: save << "LEFT\n"; break;
                case RIGHT: save << "RIGHT\n"; break;
            }
        }
        save << "/background\n";
    }

    std::vector<Object*>* fg_objs = map.getObjects("foreground");

    if(fg_objs && !fg_objs->empty())
    {
        save << "\nOBJECT_LAYER\nforeground\n";
        for(int i = 0; i < fg_objs->size(); i++)
        {
            ObjectInfo info = fg_objs->at(i)->get_info();
            save << info.type << " " << info.x << " " << info.y << " ";
            switch(info.orientation)
            {
                case UP: save << "UP\n"; break;
                case DOWN: save << "DOWN\n"; break;
                case LEFT: save << "LEFT\n"; break;
                case RIGHT: save << "RIGHT\n"; break;
            }
        }
        save << "/foreground\n";
    }

	save.close();
	std::cout << "\nMap has been saved to " << filepath << "\n";
}
